package com.skywolf.chem.match.pay.wx.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.skywolf.chem.common.sysconfig.exception.BizException;
import com.skywolf.chem.match.common.enums.MatchApplyRecordStatusEnum;
import com.skywolf.chem.match.common.enums.RefundStatusEnum;
import com.skywolf.chem.match.entity.ApplyUserRecord;
import com.skywolf.chem.match.entity.GroupInfo;
import com.skywolf.chem.match.entity.Order;
import com.skywolf.chem.match.entity.RefundOrder;
import com.skywolf.chem.match.pay.wx.config.WxPayProperties;
import com.skywolf.chem.match.pay.wx.service.PayRefundService;
import com.skywolf.chem.match.service.IApplyUserRecordService;
import com.skywolf.chem.match.service.IGroupInfoService;
import com.skywolf.chem.match.service.IOrderService;
import com.skywolf.chem.match.service.IRefundOrderService;
import com.skywolf.chem.match.utils.StringUtils;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

/**
 * @Author sj
 * Date on 2021/10/8  16:29
 * @Version 1.0
 */
@Service
@AllArgsConstructor
public class PayRefundServiceImpl implements PayRefundService {

    private final WxPayService wxPayService;

    private final IOrderService orderService;

    private final IGroupInfoService iGroupInfoService;

    private final WxPayProperties wxPayProperties;

    private final IRefundOrderService refundOrderService;

    private final IApplyUserRecordService iApplyUserRecordService;

    @Override
    public void wxPayRefund(Long orderId, Long applyUserId) throws WxPayException {
        Order order = orderService.getById(orderId);
        GroupInfo groupInfo = iGroupInfoService.getById(order.getMatchGroupId());
        if (StringUtils.isEmpty(order)) {
            throw new BizException("订单不存在！");
        }
        ApplyUserRecord record = iApplyUserRecordService.getById(applyUserId);
        if (StringUtils.isEmpty(record)) {
            throw new BizException("取消报名用户不存在！");
        }
        if (record.getApplyStatus().equals(MatchApplyRecordStatusEnum.APPLY_NORMAL_STATUS.getStatus()) ||
                record.getApplyStatus().equals(MatchApplyRecordStatusEnum.UNPAID.getStatus()) ||
                record.getApplyStatus().equals(MatchApplyRecordStatusEnum.APPLY_REFUND.getStatus())) {
            throw new BizException("当前用户不满足退款条件");
        }
        WxPayRefundV3Request request = new WxPayRefundV3Request();
        request.setOutTradeNo(order.getOutTradeNo());
        // 用户id前补零保证五位，对超出五位的保留后五位
        String userIdFilledZero = String.format("%05d", order.getMatchUserId());
        String fiveDigitsUserId = userIdFilledZero.substring(userIdFilledZero.length() - 5);
        // 在前面加上wxo（wx_refund）等前缀是为了人工可以快速分辨订单号是下单还是退款、来自哪家支付机构等
        // 将时间戳+3位随机数+五位id组成商户退款订单号
        String outRefundNo = "wx_refund_" + System.currentTimeMillis() + RandomUtil.randomNumbers(3) + fiveDigitsUserId;
        //设置退款单号
        request.setOutRefundNo(outRefundNo);
        request.setReason("取消报名退款");
        request.setNotifyUrl(wxPayProperties.getRefundNotifyUrl());
        request.setAmount(new WxPayRefundV3Request.Amount()
                .setRefund(groupInfo.getPrice().multiply(new BigDecimal(100)).intValue())
                .setTotal(order.getTotalAmount().intValue())
                .setCurrency("CNY"));
        wxPayService.refundV3(request);
        //创建退款子订单
        RefundOrder refundOrder = new RefundOrder();
        refundOrder.setOrderSn(outRefundNo);
        refundOrder.setParentOrderId(orderId);
        refundOrder.setParentOrderSn(order.getOrderSn());
        refundOrder.setRefundStatus(RefundStatusEnum.PROCESSING.getStatus());
        refundOrder.setRefundPayType(order.getPayType());
        refundOrder.setApplyUserId(applyUserId);
        refundOrder.setRefundPrice((long) request.getAmount().getRefund());
        refundOrderService.save(refundOrder);
    }
}
